<?php
class Ext_Tracker_ImportMessage extends Ext_Message
{
    const VERSION = '1.0';
    const TAB = "    ";
    private $buffer="";
    // Solo aparencen los campos obligatorios, las cosas como las properties que no son obligatorias no son validadas
    // El valor corresponde al tipo que debe tener el campo
    // "" permite que el valor este vacio, si no hay que poner "algo"
    // "DATE", "JSON", "DATE_NULL" y "JSON_NULL" son validos y significan que valide que sea una fecha o un json.
    private $order_structure = array(
                    "customer" => array(
                                    "customerId" => 0,
                                    "customerName" => "",
                                    "customerEmail" => "",
                                    "customerTel" => ""
        ),
                    "orderDate" => "DATE",
                    "paymentMethod" => array(
                                    "paymentMethodId" => 0,
                                    "ticket" => true,
                                    "description" => ""
        ),
                    "shipToAddress" => array(
                                    "addressId" => 0,
                                    "dropPoint" => "",
                                    "addressLine1" => "",
                                    "addressLine2" => "",
                                    "country" => "",
                                    "state" => "",
                                    "county" => "",
                                    "city" => "",
                                    "neighborhood" => ""
        ),
                    "billToAddress" => array(
                                    "addressId" => 0,
                                    "addressLine1" => "",
                                    "addressLine2" => "",
                                    "country" => "",
                                    "state" => "",
                                    "county" => "",
                                    "city" => "",
                                    "neighborhood" => ""
        ),
                    "shippingMethod" => array(
                                    "description" => "",
                                    "priority" => 0
        ),
                    "orderTotalAmount" => 0.0,
                    "orderShippingPrice" => 0.0,
                    "orderDiscount" => 0.0,
                    "lines" => array(
                                    "lineId" => array(
                                                    "productId" => 0,
                                                    "productDescription" => "",
                                                    "productType" => "",
                                                    "orderedQuantity" => 0,
                                                    "tax" => 0.0,
                                                    "productSellingPrice" => 0.0,
                                                    "lineShippingPrice" => 0.0,
                                                    "lineDiscount" => 0.0
            )
        )
    );

    public function __construct( $msg = null )
    {
        $this->getData( $msg );
    }

    public function getData( $msg = null )
    {
        $data = parent::getData( $msg );
        if ( $data != null ) {
            // Validate the message somehow.
            if ( ! isset( $data[ 'version' ] ) || $data[ 'version' ] != Ext_Tracker_ImportMessage::VERSION ) {
                throw new Exception( 'Tracker Import Invalid Message Version' );
            }
        } else { // Initialize Data.
            $data = array(
                            'version' => Ext_Tracker_ImportMessage::VERSION
            );
            parent::setData( $data );
        }
        return $data;
    }

    public function getOrganizationId()
    {
        $data = $this->getData();
        if ( ! isset( $data[ 'organizationId' ] ) ) {
            throw new Exception( 'Tracker Import organizationId not found' );
        }
        return $data[ 'organizationId' ];
    }

    public function setOrganizationId( $organizationId )
    {
        $data = $this->getData();
        $data[ 'organizationId' ] = $organizationId;
        parent::setData( $data );
    }

    public function getOrders()
    {
        $data = $this->getData();
        if ( ! isset( $data[ 'orders' ] ) ) {
            throw new Exception( 'Tracker Import orders not found' );
        }
        $orders = $data[ 'orders' ];
        // Validate for existence only.
        foreach ( $orders as $order_data ) {
            $msg = $this->_validate( $this->order_structure, $order_data );
            if ( $msg !== null ) {
                throw new Exception( 'Tracker Import orders not valid : ' . $msg );
            }
        }
        return $orders;
    }

    public function setOrders( $orders )
    {
        $data = $this->getData();
        $data[ 'orders' ] = $orders;
        parent::setData( $data );
    }

    public function validateImportData( $data )
    {
    	if( $this->_validate( $this->order_structure, $data) !== null ){
    		return false;
    	}
    	return true;
    }
    
    private function _validate( $structure, $data )
    {
        foreach ( $structure as $key => $val ) {
            $msg = null;
            // Hago una excepcion con el lineId (aca hay que matchear por lo menos uno, pero no se llama lineId).
            if ( $key == 'lineId' ) {
                $lines = array_keys( $data );
                if ( empty( $lines ) ) {
                    return "need at least one lineId";
                }
                foreach ( $lines as $lineId ) {
                    $msg = $this->_validate( $structure[ 'lineId' ], $data[ $lineId ] );
                }
            } else {
                if ( ! isset( $data[ $key ] ) ) {
                    return "$key must be set";
                }
                $dest = $data[ $key ];
                if ( is_array( $val ) ) {
                    $msg = $this->_validate( $structure[ $key ], $dest );
                } else {
                    if ( $val !== null ) { // con null no valido
                        if ( is_string( $val ) ) {
                            if ( empty( $dest ) ) {
                                if ( ! empty( $val ) && $val !== "JSON_NULL" && $val !== "DATE_NULL" ) {
                                    return "$key must be non empty";
                                }
                            } else {
                                if ( $val === "JSON" && json_decode( $dest ) === null ) {
                                    return "$key must be a valid JSON";
                                }
                                if ( $val === "DATE" && ! date_parse( $dest ) ) {
                                    return "$key must be a valid DATE";
                                }
                            }
                        } else if ( is_bool( $val ) ) {
                            if ( is_string( $dest ) ) {
                                if ( strcasecmp( $dest, 'true' ) && strcasecmp( $dest, 'false' ) ) {
                                    return "$key must be a valid boolean value";
                                }
                            }
                        } else if ( is_double( $val ) && ! is_numeric( $dest ) ) { // Un dobule califica si es entero.
                            return "$key must be a valid double value";
                        } else if ( is_int( $val ) && ! ( intval( $dest ) == $dest ) ) {
                            return "a $val : $dest : $key must be a valid integer value";
                        } else if ( ! is_int( $val ) && ! is_double( $val ) && ! is_bool( $val ) && ! is_string( $val ) ) {
                            if ( gettype( $val ) !== gettype( $dest ) ) {
                                return "$key must be " . gettype( $val );
                            }
                        }
                    }
                }
            }
            if ( $msg !== null ) {
                return $msg;
            }
        }
        return null;
    }

    private function prnt( $b ) 
    {
        $this->buffer .= $b;
    }

    public function printStructure() 
    {
        $this->buffer="";
        $this->prnt("* version\n".
              "* organizationId\n".
              "* orders\n".
            self::TAB."* orderId\n");
        $this->printStructureInternal( $this->order_structure, self::TAB . self::TAB );
        foreach ( explode("\n",$this->buffer) as $line ) {
            print(" " . $line . "\n");
        }
        print("(*) Mandatory\n");
        print("\n");
        print("Generated with test/importStructPrint.php\n");
    }

    private function printStructureInternal( $structure, $separator="" ) 
    {
        $separator.=self::TAB;
        foreach ( $structure as $key => $val ) {
            // Esto no esta descripto en el array, antes de lines
            if ($key=="lines") {
                $this->prnt( "$separator properties\n".
                    self::TAB."$separator"."* name : String (*)\n".
                    self::TAB.self::TAB."$separator* value : String (*)\n".
                    self::TAB.self::TAB."$separator* type name : String\n"
                );
            }

            if ( is_array( $val ) ) {
                $this->prnt("$separator* $key\n");
                $this->printStructureInternal( $structure[ $key ], $separator );
            } else {
                if ( is_null($val) ) {
                    $this->prnt("$separator* $key\n");
                } else if ( is_string( $val ) ) {
                    if ( empty($val) ) {
                        $this->prnt("$separator* $key : String (*)\n");
                        continue;
                    }
                    switch($val) {
                        case "JSON_NULL":
                            $this->prnt("$separator* $key : JSON String or null (*)\n");
                            break;
                        case "JSON":
                            $this->prnt("$separator* $key : JSON String not null (*)\n");
                            break;
                        case "DATE_NULL":
                            $this->prnt("$separator* $key : Date String or null (*)\n");
                            break;
                        case "DATE":
                            $this->prnt("$separator* $key : Date String not null (*)\n");
                            break;
                    }
                } else if ( is_bool( $val ) ) {
                    $this->prnt("$separator* $key : Boolean (*)\n");
                } else if ( is_double( $val ) ) {
                    $this->prnt("$separator* $key : Double (*)\n");
                } else if ( is_int( $val ) ) {
                    $this->prnt("$separator* $key : Integer (*)\n");
                } else {
                    $this->prnt("$separator* $key : must be " . gettype( $val ) . " (*)\n");
                }
            }
            // Esto no esta descripto en el array, al finalizar lineId
            if ($key=="lineId") {
                $this->prnt( self::TAB."$separator* properties : String\n".
                    self::TAB.self::TAB."$separator"."* name : String (*)\n".
                    self::TAB.self::TAB.self::TAB."$separator* value String (*)\n".
                    self::TAB.self::TAB.self::TAB."$separator* type String\n"
                );
            }

        }
    }
}